﻿using System.ComponentModel.Composition;

namespace SS.WPF.Framework.Display.FileDialog
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Windows.Forms;

    /// <summary>
    /// This is the default implementation of the <see cref="IFileDialogService"/>. It shows a open or save file dialog box.
    /// </summary>
    /// <remarks>
    /// If the default implementation of this service doesn't serve your need then you can provide your own implementation.
    /// </remarks>
    [Export(typeof(IFileDialogService))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class FileDialogService : IFileDialogService
    {
        /// <summary>
        /// Shows the open file dialog box that allows a user to specify a file that should be opened.
        /// </summary>
        /// <param name="fileTypes">The supported file types.</param>
        /// <param name="defaultFileType">Default file type.</param>
        /// <param name="defaultFileName">Default filename. The directory name is used as initial directory when it is specified.</param>
        /// <param name="title">Title</param>
        /// <returns>A FileDialogResult object which contains the filename selected by the user.</returns>
        /// <exception cref="ArgumentNullException">fileTypes must not be null.</exception>
        /// <exception cref="ArgumentException">fileTypes must contain at least one item.</exception>
        public FileDialogResult ShowOpenFileDialog(IEnumerable<FileType> fileTypes, FileType defaultFileType, string defaultFileName, string title)
        {
            FileDialogResult result;
            if (fileTypes != null)
            {
                if(fileTypes.Any())
                {
                    var dialog = new OpenFileDialog();
                    if (!string.IsNullOrWhiteSpace(title))
                    {
                        dialog.Title = title;
                    }
                    result = ShowFileDialog(dialog, fileTypes, defaultFileType, defaultFileName);
                }
                else
                {
                    throw new ArgumentException("The fileTypes collection must contain at least one item.");
                }
            }
            else
            {
                throw new ArgumentNullException("fileTypes");
            }
            return result;
        }

        /// <summary>
        /// Shows the save file dialog box that allows a user to specify a filename to save a file as.
        /// </summary>
        /// <param name="fileTypes">The supported file types.</param>
        /// <param name="defaultFileType">Default file type.</param>
        /// <param name="defaultFileName">Default filename. The directory name is used as initial directory when it is specified.</param>
        /// <param name="title"></param>
        /// <returns>A FileDialogResult object which contains the filename entered by the user.</returns>
        /// <exception cref="ArgumentNullException">fileTypes must not be null.</exception>
        /// <exception cref="ArgumentException">fileTypes must contain at least one item.</exception>
        public FileDialogResult ShowSaveFileDialog(IEnumerable<FileType> fileTypes, FileType defaultFileType, string defaultFileName, string title)
        {
            FileDialogResult result;
            if (fileTypes != null)
            {
                if(fileTypes.Any())
                {
                    var dialog = new SaveFileDialog();
                    if (!string.IsNullOrWhiteSpace(title))
                    {
                        dialog.Title = title;
                    }
                    result = ShowFileDialog(dialog, fileTypes, defaultFileType, defaultFileName);
                }
                else
                {
                    throw new ArgumentException("The fileTypes collection must contain at least one item.");
                }
            }
            else
            {
                throw new ArgumentNullException("fileTypes");
            }
            return result;
        }

        private static FileDialogResult ShowFileDialog(FileDialog dialog, IEnumerable<FileType> fileTypes, FileType defaultFileType, string defaultFileName)
        {
            FileDialogResult result;
            int filterIndex = fileTypes.ToList().IndexOf(defaultFileType);
            if (filterIndex >= 0)
            {
                dialog.FilterIndex = filterIndex + 1;
            }
            if (!string.IsNullOrEmpty(defaultFileName))
            {
                dialog.FileName = Path.GetFileName(defaultFileName);
                var directoryName = Path.GetDirectoryName(defaultFileName);
                string directory = AppDomain.CurrentDomain.BaseDirectory;

                if (!string.IsNullOrWhiteSpace(directoryName))
                {
                    directory = Path.GetFullPath(directoryName);
                }

                if (!Directory.Exists(directory))
                {
                    directory = AppDomain.CurrentDomain.BaseDirectory;
                }

                if (!string.IsNullOrEmpty(directory))
                {
                    dialog.InitialDirectory = directory;
                }
            }

            dialog.Filter = CreateFilter(fileTypes);
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                if (dialog.FilterIndex - 1 < fileTypes.Count())
                {
                    defaultFileType = fileTypes.ElementAt(dialog.FilterIndex - 1);
                }
                else
                {
                    defaultFileType = null;
                }
                result = new FileDialogResult(dialog.FileName, defaultFileType);
            }
            else
            {
                result = new FileDialogResult();
            }
            return result;
        }

        private static string CreateFilter(IEnumerable<FileType> fileTypes)
        {
            var filter = string.Empty;
            foreach (FileType fileType in fileTypes)
            {
                if (!String.IsNullOrEmpty(filter))
                {
                    filter += "|";
                }
                filter += fileType.Description + "|*" + fileType.FileExtension;
            }
            return filter;
        }
    }
}
